﻿﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Datamining.Models;

namespace Datamining.Program
{
    public class UserPreferences
    {
        #region Fields

        public int UserId { get; set; }
        private int[] itemids = new int[1];
        private double[] preferences = new double[1];

        #endregion

        #region Zoek methodes

        /// <summary>
        /// Geeft de rating waarde terug van de ingevoerde itemId.
        /// </summary>
        /// <param name="itemId"></param>
        /// <returns>Double rating waarde a.d.h.v. de itemId.</returns>
        public double getRatingByItemId(int itemId)
        {
            return preferences[getIndexOfItemId(itemId)];
        }

        /// <summary>
        /// Geeft een index value terug waarop een itemId te vinden is.
        /// </summary>
        /// <param name="itemId"></param>
        /// <returns>int index waarde waarop de itemId te vinden is.</returns>
        private int getIndexOfItemId(int itemId)
        {
            int index = Array.BinarySearch(itemids, itemId); // Index < 0 dan is invoegplaats = index * (-1) + 1

            return index;
        }

        /// <summary>
        /// Krijg alle artikelen die niet beoordeeld zijn door de gebruiker
        /// </summary>
        /// <param name="userId"></param>
        /// <returns>Returned een int[] die gevuld is met itemId die de gebruiker nog niet heeft gerate.</returns>
        public int[] GetArticlesNotRatedByUser()
        {
            int[] notRatedbyUser = new int[Program.itemDictionary.Count];
            int current = 0;

            foreach (KeyValuePair<int, Items> v in Program.itemDictionary)
            {
                if (!itemids.Contains(v.Value.id))
                {
                    notRatedbyUser[current] = v.Value.id;
                }
                current++;
            }
            return notRatedbyUser;
        }

        /// <summary>
        /// Geeft alle overeenkomstige items van twee users terug
        /// </summary>
        /// <param name="u1"></param>
        /// <param name="u2"></param>
        /// <returns>Een int[] die bestaat uit een lijst van itemdId die ze beiden hebben gerate.</returns>
        public int[] CommonItems(UserPreferences u1)
        {
            int[] itemsuser = new int[Program.itemDictionary.Count];
            int current = 0;
            // return waarde record data die heeft attributen: int[] itemIds, double[] ratingUser1, double[] ratingUser2

            foreach (KeyValuePair<int, Items> v in Program.itemDictionary)
            {
                if (u1.getItemIdArray().Contains(v.Value.id) && this.itemids.Contains(v.Value.id))
                {
                    itemsuser[current] = v.Value.id;
                }
                current++;
            }
            return itemsuser;
        }

        #endregion

        #region Insert en vergroot methodes voor de arrays items en preferences.

        /// <summary>
        /// De itemId en bijbehorende rating wordt in de juiste array opgeslagen. Als een item al een rating heeft wordt het overschreven.
        /// Het zorgt na de invoer ervoor dat de index van beide arrays klopt.
        /// </summary>
        /// <param name="itemId"></param>
        /// <param name="rating"></param>
        public void setItemIDRating(int itemId, double rating)
        {
            // index groter of gelijk aan 0 dan overschrijven anders bestaat hij nog niet.
            int indexItemId = getIndexOfItemId(itemId);

            if (indexItemId >= 0)
            {
                itemids[indexItemId] = itemId;
                preferences[indexItemId] = rating;
            }
            else
            {
                InsertInItemId(itemId);
                InsertInPreferences(rating);
            }

            // Sorteer de itemids array van laag naar hoog en pas daarbij de bijbehorende index van de rating ook aan in de preferences array.
            Array.Sort(itemids, preferences);
        }


        /// <summary>
        /// Voegt de parameter in de array of vergroot de array.
        /// </summary>
        /// <param name="itemId"></param>
        private void InsertInItemId(int itemId)
        {
            if (itemids[itemids.Length - 1] == 0)
            {
                itemids[itemids.Length - 1] = itemId;
            }
            else
            {
                itemids = IncreaseArrayItems(itemids, itemId);
            }
        }

        /// <summary>
        /// Voegt de parameter in de array of vergroot de array.
        /// </summary>
        /// <param name="preference"></param>
        private void InsertInPreferences(double preference)
        {
            if (preferences[preferences.Length - 1] == 0)
            {
                preferences[preferences.Length - 1] = preference;
            }
            else
            {
                preferences = IncreaseArrayPreferences(preferences, preference);
            }
        }

        /// <summary>
        /// Vergroot de array Items zodat er nieuwe data ingevoerd kan worden.
        /// </summary>
        /// <param name="original"></param>
        /// <param name="itemId"></param>
        /// <returns>Geeft een grotere array terug met de oorspronkelijke data.</returns>
        private int[] IncreaseArrayItems(int[] original, int itemId)
        {
            int length = original.Count();
            int[] destination = new int[length + 1];

            Array.Copy(original, 0, destination, 0, length);
            destination[length] = itemId;

            return destination;
        }

        /// <summary>
        /// Vergroot de array Preferences zodat er nieuwe data ingevoerd kan worden.
        /// </summary>
        /// <param name="original"></param>
        /// <param name="itemId"></param>
        /// <returns>Geeft een grotere array terug met de oorspronkelijke data.</returns>
        private double[] IncreaseArrayPreferences(double[] original, double itemId)
        {
            int length = original.Count();
            double[] destination = new double[length + 1];

            Array.Copy(original, 0, destination, 0, length);
            destination[length] = itemId;

            return destination;
        }

        #endregion

        #region Print methodes

        /// <summary>
        /// Print alle gegevens van de huidige UserPreference uit.
        /// </summary>
        public void printAllUserPreferenceData()
        {
            for (int i = 0; i < itemids.Length; i++)
            {
                Console.WriteLine("UserID: " + UserId + " || ItemID: " + itemids[i] + " || Prefs: " + preferences[i]);
            }
            Console.ReadLine();
        }

        #endregion

        #region getters en setters

        public int[] getItemIdArray()
        {
            return itemids;
        }

        public double[] getRatingArray()
        {
            return preferences;
        }

        #endregion
    }
}
